/**
 * 奖励
 *
 * @format
 */

import { BaseDao, resultsModel } from '../../sdk'
import UserService from './user.service'
import {
  CODE_TYPES,
  DRAW_STATUS,
  PRIZE_TYPE,
  ACTIVITY_STATUS,
  DELETE_STATUS,
  SWICH_TOCK,
  SHIP_STATUS,
  ACTIVITY_OPEN_PRIZE_STATUS,
  BENEFIT_TYPE,
  PRIZE_DATA_TYPE,
  THIRTY_DAY,
  SELLER_SHOP_CONFIG
} from '../../constants'
import { AWARDS_DB_NAME, PRIZE_CONFIG_DB_NAME } from '../../db'
import { sendTBAward, getSellerSession, rand, formatPrizeProbalityRange } from '../../utils'
import { generateCodeTypeWithMsg } from '../../utils/common/helper'
import { getToday } from '../../utils/common/getToday'
import { getAwardValidTime } from '../../utils/custom/getAwardValidTime'
import { sendQimenRequest } from '../../utils/common/qimen'

export default class AwardsService extends UserService {
  awardsdao: IBaseDao
  activityprizedao: IBaseDao
  constructor(context: IContext<IParams>) {
    super(context)
    this.awardsdao = new BaseDao(context, AWARDS_DB_NAME)
    this.activityprizedao = new BaseDao(context, PRIZE_CONFIG_DB_NAME)
  }

  // 根据奖品Id扣库存, 扣库存成功返回为1
  async reduceStock(_id: string) {
    let result = await this.activityprizedao.findOne<IActivityPrize>({ _id, deleteStatus: ACTIVITY_STATUS.NORMAL })
    // 奖品不存在
    if (!result) {
      return CODE_TYPES.ERROR_NO_PRIZE
    }
    let { switchStock, stock, useStock } = result
    // 若不限制库存
    if (switchStock === SWICH_TOCK.NO_LIMIT) {
      return 1
    }
    // 若库存不足
    if (useStock >= stock) {
      return CODE_TYPES.ERROR_NO_STOCK
    }
    try {
      const updateResult = await this.activityprizedao.update(
        {
          _id,
          $where: 'this.useStock < this.stock'
        },
        {
          $inc: {
            useStock: +1
          }
        }
      )
      return updateResult === 1 ? 1 : CODE_TYPES.ERROR_NO_STOCK
    } catch (e) {
      console.log(`扣库存失败：`, e)
      return CODE_TYPES.SYSTEM_ERROR
    }
  }

  async getMyPrizeList(activityInfo: IActivityInfo) {
    const { openId } = this.context
    const { activityId } = this.context.data
    const myPrizeList = await this.getAwardsInfoList(
      {
        openId,
        activityId,
        type: { $ne: PRIZE_TYPE.THANKS }
      },
      {
        projection: {
          prizeId: 1,
          _id: 1,
          name: 1,
          image: 1,
          type: 1,
          drawStatus: 1,
          shipStatus: 1,
          remark: 1,
          useUrl: 1,
          shipCompany: 1,
          shipNum: 1,
          benefitType: 1,
          ename: 1,
          expiredTime: 1,
          failureTime: 1
        },
        sort: {
          createTime: -1
        }
      }
    )

    return {
      list: this.formatMyPrizeList(myPrizeList, activityInfo)
    }
  }

  /**
   * 插入奖品记录
   * @param {*} award
   */
  async addAward(award: IAwards) {
    return await this.awardsdao.insertOne({
      ...award,
      shipStatus: award?.type === PRIZE_TYPE.OBJECT ? SHIP_STATUS.NO_ADDRESS : '',
      createTime: Date.now(),
      updateTime: Date.now()
    })
  }

  /**
   * 发放奖品
   * @param {*} document
   */
  async sendAward(document: IAwards) {
    let { session } = await getSellerSession(this.context)
    // 发放淘宝权益
    let result = await sendTBAward(this.context, session, document)
    //@ts-ignore
    if (result.code) {
      return result
    }
    let { _id } = document

    // 更新结果
    let update = await this.awardsdao.update(
      { _id },
      {
        $set: {
          drawStatus: document.drawStatus,
          remark: document.remark,
          updateTime: Date.now()
        }
      }
    )
    console.log(`更新奖品状态`, update, document)
    return document
  }

  async getAwardsInfoList(query: object, projection?: IFindProjection) {
    return await this.awardsdao.find<IAwards>(query, projection)
  }

  formatMyPrizeList(myPrizeList: IAwards[], activityInfo: IActivityInfo): IAwards[] {
    return myPrizeList.map(v => {
      if (Date.now() > getAwardValidTime(activityInfo, v)) {
        v.drawStatus = DRAW_STATUS.EXPIRED
        v.remark = `奖品已过期`
      }
      return {
        ...v,
        id: v._id
      }
    })
  }

  // 领取实物
  async recieveObjectPrize(context: IContext<IParams>) {
    let { province, city, area, streetName, addressDetail, id, name, phone, size } = context.data

    let result = await this.awardsdao.update(
      { _id: id },
      {
        $set: {
          size,
          receiveName: name,
          phone,
          drawStatus: DRAW_STATUS.SUCCESS,
          shipStatus: SHIP_STATUS.NO_SHIP,
          province,
          city,
          area,
          streetName,
          addressDetail,
          receiveTime: Date.now(),
          updateTime: Date.now()
        }
      }
    )
    return result
      ? { province, city, area, streetName, addressDetail, id, name, phone }
      : CODE_TYPES.ERROR_RECEIVE_PRIZE
  }

  // 发放淘宝权益（奖品数据已插入到awards_info表，且状态drawStatus 为1或者6）
  async recieveEnamePrize(_id: string, awardInfo: IAwards, session: string) {
    let result
    // 判断权益类型
    const { type, benefitType } = awardInfo
    if (type === PRIZE_TYPE.ENAME && benefitType === BENEFIT_TYPE.MEMBER) {
      // 会员权益，前端领取成功
      result = {
        drawStatus: DRAW_STATUS.SUCCESS,
        remark: ''
      }
    } else {
      // 发放淘宝权益
      result = await sendTBAward(this.context, session, awardInfo)
    }
    // 更新
    await this.awardsdao.update(
      { _id },
      {
        $set: {
          // @ts-ignore
          drawStatus: result.drawStatus,
          // @ts-ignore
          remark: result.remark,
          updateTime: Date.now()
        }
      }
    )
    if ((result as IAwards).remark) {
      return generateCodeTypeWithMsg(CODE_TYPES.SYSTEM_ERROR, (result as IAwards).remark)
    }
    return result
  }

  // async drawLottery(
  //   activityInfo: IActivityInfo,
  //   userInfo: IUserInfo,
  //   joinInfo: IJoinRecord,
  //   probability: IProbabilityConfig
  // ) {
  //   const prizeDataType = PRIZE_DATA_TYPE.LUCK
  //   const { openId, data } = this.context
  //   const { activityId } = data

  //   const randSeed = rand(10000)
  //   const { properiodfrom, properiodto } = probability

  //   let prize

  //   // 获取奖池配置
  //   const prizesPool = await this.getPrizeConfig({
  //     activityId,
  //     // 根据需求配置筛选条件
  //     prizeDataType
  //   })

  //   // 谢谢参与
  //   const thanksPrize = prizesPool.find(v => v.type === PRIZE_TYPE.THANKS) || {
  //     type: PRIZE_TYPE.THANKS,
  //     prizeDataType,
  //     name: '谢谢参与'
  //   }

  //   let pass = false

  //   // 满足条件必中小老虎
  //   if (joinInfo.score > 18887) {
  //     prize = (await this.getPrizeConfig({ activityId, prizeDataType })).find(itm => itm.type === PRIZE_TYPE.CARD)
  //     if (prize && prize.failureTime && prize.failureTime > Date.now()) {
  //       const sendResult = await this.sendMainAvatar(this.context, activityInfo)
  //       // 小老虎发放成功
  //       if (sendResult) {
  //         pass = true
  //       }
  //     }
  //   }

  //   if (!pass) {
  //     if (randSeed >= properiodfrom && randSeed <= properiodto) {
  //       prize = await this.getPrizeByProbability(prizesPool, joinInfo)
  //       // 未找到奖品,降级到谢谢参与
  //       if (!prize) {
  //         prize = thanksPrize
  //       }
  //     } else {
  //       prize = thanksPrize
  //     }

  //     if (prize.type !== PRIZE_TYPE.THANKS) {
  //       const { failureTime } = prize
  //       if (failureTime && Date.now() > failureTime) {
  //         prize = thanksPrize
  //       }
  //     }

  //     if (prize.type !== PRIZE_TYPE.THANKS) {
  //       // 活动奖品一次限制
  //       const { list: myPrizeList } = await this.getMyPrizeList(activityInfo)
  //       if (activityInfo.isWinPrizeOnce && myPrizeList?.length > 0) {
  //         prize = thanksPrize
  //       }

  //       // 活动奖品周期限制
  //       const activityIds = await this.getCurrentBaseInfoList()
  //       const totalMyPrizeList = await this.getAwardsInfoList(
  //         { openId, type: { $ne: PRIZE_TYPE.THANKS }, activityId: { $in: activityIds.map(v => v['_id']) } },
  //         { sort: { createTime: -1 } }
  //       )
  //       if (prize.type !== PRIZE_TYPE.THANKS && activityInfo.winPrizeLimitDay) {
  //         const lastPrize = totalMyPrizeList[0]
  //         if (lastPrize && Date.now() - lastPrize.createTime < activityInfo.winPrizeLimitDay * 24 * 60 * 60 * 1000) {
  //           prize = thanksPrize
  //         }
  //       }

  //       // 单独奖品一次限制
  //       if (
  //         prize.type !== PRIZE_TYPE.THANKS &&
  //         prize.isWinPrizeOnce &&
  //         myPrizeList.find(itm => itm.prizeId === prize._id)
  //       ) {
  //         prize = thanksPrize
  //       }

  //       // 每日库存限制
  //       if (prize.type !== PRIZE_TYPE.THANKS && prize.dailyStockLimit > 0) {
  //         let updateResult = await this.activityprizedao.update(
  //           {
  //             _id: prize._id,
  //             $where: `(this.dailyUseStock ? (this.dailyUseStock['${getToday()}'] || 0) : 0) < this.dailyStockLimit`
  //           },
  //           { $inc: { [`dailyUseStock.${getToday()}`]: 1 } }
  //         )
  //         if (updateResult !== 1) {
  //           prize = thanksPrize
  //         }
  //       }
  //     }

  //     let reduceResult: ICodeType | number = 1

  //     if (prize.type !== PRIZE_TYPE.THANKS) {
  //       reduceResult = await this.reduceStock(prize._id)
  //       // 扣库存失败降级到降级奖品
  //       if ((reduceResult as ICodeType)?.code || !reduceResult) {
  //         // 如果有每日限制 返还每日限制
  //         if (prize.dailyStockLimit > 0) {
  //           await this.activityprizedao.update({ _id: prize._id }, { $inc: { [`dailyUseStock.${getToday()}`]: -1 } })
  //         }
  //         prize = thanksPrize
  //       }
  //     }

  //     if (prize.type === PRIZE_TYPE.CARD) {
  //       console.log(prize, '小老虎')
  //       const sendResult = await this.sendMainAvatar(this.context, activityInfo)
  //       console.log(sendResult)
  //       if (!sendResult) {
  //         prize = thanksPrize
  //       }
  //     }
  //   }

  //   const { type, _id, ename, image, name, useUrl, credits, benefitType, failureTime } = prize

  //   const { userNick } = userInfo
  //   let record = {
  //     openId,
  //     prizeId: _id,
  //     activityId,
  //     drawStatus: type === PRIZE_TYPE.CARD ? DRAW_STATUS.SUCCESS : DRAW_STATUS.WAITAWARD,
  //     prizeDataType,
  //     remark: '',
  //     useUrl,
  //     type,
  //     benefitType,
  //     ename,
  //     name,
  //     image,
  //     credits: +credits,
  //     userNick,
  //     createDay: getToday(),
  //     expiredTime: Date.now() + THIRTY_DAY,
  //     failureTime
  //   }

  //   // 奖品信息 insert c_awards表
  //   const result = await this.addAward(record)

  //   return {
  //     prizeId: _id,
  //     id: result,
  //     type,
  //     benefitType,
  //     ename,
  //     name,
  //     image
  //   }
  // }

  // 发放用户主会场头像
  // async sendMainAvatar(context, activityInfo: IActivityInfo) {
  //   //发送虎年头像参数
  //   const body = {
  //     ouid: '$top_ouid$',
  //     avatar_name: '2022-tiger-cny',
  //     shop_id: activityInfo.shopId,
  //     channel: 'PILE'
  //   }
  //   const qimenRealPath =
  //     context.env == 'test' ? API_URL_LIST.SEND_AVATAR.sbdQimenPath : API_URL_LIST.SEND_AVATAR.qimenPath
  //   const result = await sendQimenRequest(context, qimenRealPath, body, SELLER_SHOP_CONFIG[activityInfo.shopId])
  //   return result?.success
  // }

  // 根据查询条件获取奖品配置
  async getPrizeConfig(
    query: { activityId: string; [queryParam: string]: any },
    projection: IFindProjection = {}
  ): Promise<IActivityPrize[]> {
    return this.activityprizedao.find<IActivityPrize>(
      {
        deleteStatus: DELETE_STATUS.NORMAL,
        ...query
      },
      projection
    )
  }

  // 根据概率抽取奖品
  async getPrizeByProbability(prizes: IActivityPrize[], joinInfo: IJoinRecord): Promise<IActivityPrize> {
    // 获取 1-10000的随机数
    const probability = rand(10000)

    if (joinInfo.useTimeToolCount > 0) {
      // 使用加时卡
      return formatPrizeProbalityRange(prizes).find(
        v => probability <= v.useCard.properiodto && probability >= v.useCard.properiodfrom
      )
    } else {
      // 未使用加时卡
      return formatPrizeProbalityRange(prizes).find(
        v => probability <= v.notUseCard.properiodto && probability >= v.notUseCard.properiodfrom
      )
    }
  }

  /**
   * 获取活动配置项奖品
   * @param {string} _id
   */
  async getActivityPrizeById(_id: string): Promise<IActivityPrize> {
    return await this.activityprizedao.findOne(
      { _id, deleteStatus: ACTIVITY_STATUS.NORMAL },
      {
        sort: {
          index: 1
        }
      }
    )
  }

  /**
   * 排行榜开奖
   * @param activityInfo
   * @param prizeDataType
   * @param sortKey
   * @param sortTimeKey
   * @param limit
   */
  async openPrize(activityList, prizeDataType, sortKey: string, sortTimeKey: string, limit?: number) {
    const fail = []
    const success = []
    for (let activityInfo of activityList) {
      const { _id } = activityInfo
      await this.activitydao.update({ _id }, { $set: { openPrizeStatus: ACTIVITY_OPEN_PRIZE_STATUS.OPENING } })
      const prizeConfigList = await this.getPrizeConfig({
        activityId: _id,
        prizeDataType
      })
      const userList = await this.userdao.find<IUserInfo>(
        {
          activityId: _id
        },
        {
          sort: { [sortKey]: -1, [sortTimeKey]: 1 },
          limit: limit || 100
        }
      )
      const prizeList = []
      prizeConfigList.forEach(prizeConfig => {
        const { rank, _id: prizeId, type, name, ename, image, credits, benefitType } = prizeConfig
        let [min, max] = rank.split('-')
        if (!max) max = min
        for (let i = +min - 1; i < +max; i++) {
          if (userList[i]) {
            const { openId, userNick } = userList[i]
            prizeList.push({
              openId,
              prizeId,
              activityId: _id,
              drawStatus: DRAW_STATUS.WAITAWARD,
              prizeDataType,
              remark: '',
              credits: +credits,
              benefitType,
              ename,
              type,
              name,
              image,
              userNick,
              createDay: getToday(),
              shipStatus: type === PRIZE_TYPE.OBJECT ? SHIP_STATUS.NO_ADDRESS : '',
              createTime: Date.now(),
              updateTime: Date.now()
            })
          }
        }
      })
      let result = null
      if (prizeList.length) {
        result = await this.awardsdao.insertMany(prizeList)
      }
      if (result) {
        await this.activitydao.update({ _id }, { $set: { openPrizeStatus: ACTIVITY_OPEN_PRIZE_STATUS.SUCCESS } })
        success.push(_id)
      } else {
        await this.activitydao.update({ _id }, { $set: { openPrizeStatus: ACTIVITY_OPEN_PRIZE_STATUS.FAIL } })
        fail.push(_id)
      }
    }
    return { success, fail }
  }
}
